#include "SipCore.h"
#define THIS_FILE "SipCore.cpp"

SipCore::SipCore(QObject *parent)
	: QObject(parent)
{
	m_AccountID_Map.clear();
	initail();
}

SipCore::~SipCore()
{
	QMap<QString,pjsua_acc_id>::Iterator iter = m_AccountID_Map.begin();
	for (;iter != m_AccountID_Map.end(); ++iter)
	{
		pjsua_acc_del(iter.value());
	}
	m_AccountID_Map.clear();
}

pj_status_t SipCore::registerSipAccount(const char *callerid, const char *username, const char *password, const char *domain)
{	
	/* Register to SIP server by creating SIP account. */
	pj_status_t status;
	pjsua_acc_config cfg;

	pjsua_acc_config_default(&cfg);
	cfg.id = pj_str(QString("sip:%1@%2").arg(callerid).arg(domain).toLocal8Bit().data());
	cfg.reg_uri = pj_str(QString("sip:%1").arg(domain).toLocal8Bit().data());
	cfg.cred_count = 1;
	cfg.cred_info[0].realm = pj_str((char*)domain);
	cfg.cred_info[0].scheme = pj_str("digest");
	cfg.cred_info[0].username = pj_str((char*)username);
	cfg.cred_info[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
	cfg.cred_info[0].data = pj_str((char*)password);

	pjsua_acc_id acc_id;
	status = pjsua_acc_add(&cfg, PJ_TRUE, &acc_id);
	if (status != PJ_SUCCESS) 
		return errorExit("Error adding account", status);

	m_AccountID_Map.insert(callerid,acc_id);
	return status;
}

pj_status_t SipCore::unRegisterSipAccount(const char *callerid)
{
	pj_status_t status;
	if(m_AccountID_Map.contains(callerid))
		status = pjsua_acc_del(m_AccountID_Map.take(callerid));
	return status;
}

pj_status_t SipCore::callAnswer(pjsua_call_id call_id)
{
	/* Automatically answer incoming calls with 200/OK */
	pjsua_call_answer(call_id, 200, NULL, NULL);
}

pj_status_t SipCore::initail(void)
{
	pj_status_t status;

	/* Create pjsua first! */
	status = pjsua_create();
	if (status != PJ_SUCCESS) 
		return errorExit("Error in pjsua_create()", status);

	/* Init pjsua */
	{
		pjsua_config cfg;
		pjsua_logging_config log_cfg;

		pjsua_config_default(&cfg);
		cfg.cb.on_incoming_call = &SipCore::onEventIncomingCall;
		cfg.cb.on_call_media_state = &SipCore::onEventCallMediaState;
		cfg.cb.on_call_state = &SipCore::onEventCallState;

		pjsua_logging_config_default(&log_cfg);
		log_cfg.console_level = 4;
		log_cfg.log_filename = pj_str("MyPhone.log");

		status = pjsua_init(&cfg, &log_cfg, NULL);
		if (status != PJ_SUCCESS) 
			return errorExit("Error in pjsua_init()", status);
	}

	/* Add UDP transport. */
	{
		status = setUdpTransPort(16069);
		if (status != PJ_SUCCESS) 
			return errorExit("Error creating transport", status);
	}

	/* Initialization is done, now start pjsua */
	status = pjsua_start();
	if (status != PJ_SUCCESS) 
		return errorExit("Error starting pjsua", status);

	return status;
}

pj_status_t SipCore::errorExit(const char *title, pj_status_t status)
{
	emit errorMessage(title);
	pjsua_perror(THIS_FILE, title, status);
	pjsua_destroy();
	return status;
}

pj_status_t SipCore::setUdpTransPort(unsigned port)
{
	pjsua_transport_config cfg;
	pjsua_transport_config_default(&cfg);
	cfg.port = port;
	return pjsua_transport_create(PJSIP_TRANSPORT_UDP, &cfg, NULL);
}

void SipCore::onEventIncomingCall(pjsua_acc_id acc_id, pjsua_call_id call_id,pjsip_rx_data *rdata)
{
	pjsua_call_info ci;

	PJ_UNUSED_ARG(acc_id);
	PJ_UNUSED_ARG(rdata);

	pjsua_call_get_info(call_id, &ci);

	PJ_LOG(3,(THIS_FILE, "Incoming call from %.*s!!",
		(int)ci.remote_info.slen,
		ci.remote_info.ptr));

	emit evtCallAnswer((int)acc_id);

}
void SipCore::onEventCallMediaState(pjsua_call_id call_id)
{
	pjsua_call_info ci;

	pjsua_call_get_info(call_id, &ci);

	if (ci.media_status == PJSUA_CALL_MEDIA_ACTIVE) {
		// When media is active, connect call to sound device.
		pjsua_conf_connect(ci.conf_slot, 0);
		pjsua_conf_connect(0, ci.conf_slot);
	}

}
void SipCore::onEventCallState(pjsua_call_id call_id, pjsip_event *e)
{
	pjsua_call_info ci;

	PJ_UNUSED_ARG(e);

	pjsua_call_get_info(call_id, &ci);
	PJ_LOG(3,(THIS_FILE, "Call %d state=%.*s", call_id,
		(int)ci.state_text.slen,
		ci.state_text.ptr));

}